//
//  YTScrollGestureControl.swift
//  UIKit物理效果
//
//  Created by 柯南 on 2022/9/16.
//

//MARK:- 单一个TableView 的手势滚动

import UIKit

// tableView 通过手势进行滚动
class YTScrollGestureControl: NSObject {
    // referenceView 添加在最底层的 view 上
    var referenceView: YTReferenceView
    var tableView: UITableView

    lazy var animator = UIDynamicAnimator(referenceView: self.referenceView)
    lazy var item = YTItemBehavior()

    //MARK:- data
    // 拖动起始Y值
    var beginOffsetY: CGFloat = 0

    // 当前tabview偏移Y值
    var currentOffsetY: CGFloat = 0

    // 当前ItemBehavior中心Y值
    var itemCenterY: CGFloat = 0

    // 旧的ItemBehavior中心Y值
    var oldItemCenterY: CGFloat = 0

    // tableView offsetY 起点
    var tableViewBeganOffsetY: CGFloat { -tableView.contentInset.top }

    // tableView offsetY 终点
    var tableViewMaxOffsetY: CGFloat {
        tableView.contentSize.height - tableView.bounds.height + (tableView.contentInset.bottom)
    }

    /// 初始化
    /// - Parameters:
    ///   - referenceView: 最底层的 view
    ///   - tableView: tableView
    init(referenceView: YTReferenceView, tableView: UITableView) {
        self.referenceView = referenceView
        self.tableView = tableView

        super.init()
        setup()
    }

    func setup() {
        self.tableView.isScrollEnabled = false
        self.tableView.bounces = false

        // 长按收拾，主要控制滚动与惯性
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panGesture(_:)))
        self.referenceView.addGestureRecognizer(panGesture)

        // 点击手势主要负责控制cell的点击
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapGesture(_:)))
        self.tableView.addGestureRecognizer(tapGesture)

        // 负责惯性滚动时的点击停止滚动
        referenceView.touchBeganCallBack = { [weak self] in
            self?.behaviorEndAnimation()
        }
    }
}

//MARK:- Action
extension YTScrollGestureControl {
    @objc func tapGesture(_ gesture: UITapGestureRecognizer) {
        let point = gesture.location(in: tableView)
        if let indexPath = tableView.indexPathForRow(at: point) {
            tableView.delegate?.tableView?(tableView, didSelectRowAt: indexPath)
        }
    }

    @objc func panGesture(_ gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .began:
            gestureBegan(gesture)
            break
        case .ended:
            gestureEnded(gesture)
            break
        case .changed:
            gestureChanged(gesture)
            break
        case .possible:
            tableViewUserInteractionEnabledState(true)
            break
        case .cancelled:
            tableViewUserInteractionEnabledState(true)
            break
        case .failed:
            tableViewUserInteractionEnabledState(true)
            break
        @unknown default:
            tableViewUserInteractionEnabledState(true)
            break
        }
    }

    /// 手势开始
    func gestureBegan(_ gesture: UIPanGestureRecognizer) {
        animator.removeAllBehaviors()

        beginOffsetY = gesture.location(in: self.referenceView).y
        currentOffsetY = tableView.contentOffset.y
        itemCenterY = item.center.y
    }

    /// 手势结束
    func gestureEnded(_ gesture: UIPanGestureRecognizer) {
        // 计算惯性滚动
        currentOffsetY = tableView.contentOffset.y
        let pointY = gesture.velocity(in: self.referenceView).y

        if abs(pointY) >= 180 { // 设置滑动速度大于180才执行惯性动画

            let behavior = UIDynamicItemBehavior(items: [item])
            behavior.resistance = 1.57
            behavior.addLinearVelocity(.init(x: 0, y: pointY), for: item)

            behavior.action = { [weak self] in // 根据惯性进行滚动
                guard let weakSelf = self else { return }

                // 即将结束惯性
                if abs(weakSelf.item.center.y - weakSelf.oldItemCenterY) < 0.02 {
                    weakSelf.behaviorWillEndAnimation()
                }else {
                    weakSelf.tableViewUserInteractionEnabledState(false)
                }

                let newOffsetY = weakSelf.setTabViewContentOffset(weakSelf.item.center.y, beginOffsetY: weakSelf.itemCenterY)
                weakSelf.oldItemCenterY = weakSelf.item.center.y

                // 到顶部或底部
                if newOffsetY <= weakSelf.tableViewBeganOffsetY || newOffsetY >= weakSelf.tableViewMaxOffsetY {
                    weakSelf.behaviorEndAnimation()
                }
            }

            animator.addBehavior(behavior)
        }else { // 不需要惯性
            tableViewUserInteractionEnabledState(true)
        }
    }

    /// 手势改变
    func gestureChanged(_ gesture: UIPanGestureRecognizer) {
        let currentY = gesture.location(in: self.referenceView).y

        // 设置滚动
        tableViewUserInteractionEnabledState(false)
        setTabViewContentOffset(currentY, beginOffsetY: beginOffsetY)
    }

    /// 设置列表的 offset
    @discardableResult
    func setTabViewContentOffset(_ offsetY: CGFloat, beginOffsetY: CGFloat) -> CGFloat {
        let offsetY = -(offsetY - beginOffsetY) + self.currentOffsetY
        var newOffsetY = offsetY >= tableViewBeganOffsetY ? offsetY : tableViewBeganOffsetY
        newOffsetY = newOffsetY >= tableViewMaxOffsetY ? tableViewMaxOffsetY : newOffsetY

        tableView.contentOffset.y = newOffsetY
        return newOffsetY
    }

    /// 惯性动画即将结束
    func behaviorWillEndAnimation() {
        tableViewUserInteractionEnabledState(true)
    }

    /// 结束惯性动画
    func behaviorEndAnimation() {
        animator.removeAllBehaviors()
        tableViewUserInteractionEnabledState(true)
    }

    /// 设置 tableView 是否允许交互
    func tableViewUserInteractionEnabledState(_ state: Bool) {
        tableView.isUserInteractionEnabled = state
    }
}

//class YTItemBehavior: NSObject, UIDynamicItem {
//    var center: CGPoint
//
//    var bounds: CGRect
//
//    var transform: CGAffineTransform
//
//    override init() {
//        bounds = .init(x: 0, y: 0, width: 1, height: 1)
//        center = .zero
//        transform = .identity
//    }
//}
//
//class YTReferenceView: UIView {
//    var touchBeganCallBack: (() -> Void)?
//
//    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
//        touchBeganCallBack?()
//    }
//}
